Skip to content

Conversation

@mgcarrasco
Copy link
Contributor

SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst asserted that it always expected a GetElementPtrInst from IRBuilder::CreateGEP (which returns a Value). IRBuilder can fold and return a ConstantExpr instead, thus violating the assertion. The patch fixes this by using GetElementPtrInst::Create to always return a GetElementPtrInst.

This LLVM defect was identified via the AMD Fuzzing project.

@llvmbot
Copy link
Member

llvmbot commented Dec 3, 2025

@llvm/pr-subscribers-backend-spir-v

Author: Manuel Carrasco (mgcarrasco)

Changes

SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst asserted that it always expected a GetElementPtrInst from IRBuilder::CreateGEP (which returns a Value). IRBuilder can fold and return a ConstantExpr instead, thus violating the assertion. The patch fixes this by using GetElementPtrInst::Create to always return a GetElementPtrInst.

This LLVM defect was identified via the AMD Fuzzing project.


Full diff: https://github.com/llvm/llvm-project/pull/170524.diff

2 Files Affected:

  • (modified) llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp (+2-5)
  • (added) llvm/test/CodeGen/SPIRV/const-array-gep.ll (+19)
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index eea49bfdaf04b..736020406ce96 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -2816,13 +2816,10 @@ SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) {
   ArrayType *ArrTy = dyn_cast<ArrayType>(SrcTy);
   if (ArrTy && ArrTy->getNumElements() == 0 &&
       PatternMatch::match(Indices[0], PatternMatch::m_Zero())) {
-    IRBuilder<> Builder(GEP);
     Indices.erase(Indices.begin());
     SrcTy = ArrTy->getElementType();
-    Value *NewGEP = Builder.CreateGEP(SrcTy, GEP->getPointerOperand(), Indices,
-                                      "", GEP->getNoWrapFlags());
-    assert(llvm::isa<GetElementPtrInst>(NewGEP) && "NewGEP should be a GEP");
-    return cast<GetElementPtrInst>(NewGEP);
+    return GetElementPtrInst::Create(SrcTy, GEP->getPointerOperand(), Indices,
+                                     GEP->getNoWrapFlags(), "", GEP);
   }
   return nullptr;
 }
diff --git a/llvm/test/CodeGen/SPIRV/const-array-gep.ll b/llvm/test/CodeGen/SPIRV/const-array-gep.ll
new file mode 100644
index 0000000000000..c1dfe18aee6e6
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/const-array-gep.ll
@@ -0,0 +1,19 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown < %s | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown < %s -filetype=obj | spirv-val %}
+
+define spir_kernel void @_Z6kernelPi() addrspace(4) {
+; CHECK-LABEL: _Z6kernelPi
+; CHECK:       %12 = OpFunction %3 None %4 ; -- Begin function _Z6kernelPi
+; CHECK-NEXT:    %2 = OpLabel
+; CHECK-NEXT:    %13 = OpBitcast %6 %11
+; CHECK-NEXT:    %14 = OpInBoundsPtrAccessChain %6 %13 %10
+; CHECK-NEXT:    %15 = OpConvertPtrToU %5 %14
+; CHECK-NEXT:    %16 = OpBitcast %6 %11
+; CHECK-NEXT:    OpStore %16 %15 Aligned 4
+; CHECK-NEXT:    OpReturn
+; CHECK-NEXT:    OpFunctionEnd
+entry:
+  store i32 ptrtoint (ptr addrspace(4) getelementptr inbounds ([0 x i32], ptr addrspace(4) null, i64 0, i64 1) to i32), ptr addrspace(4) null, align 4
+  ret void
+}

@mgcarrasco mgcarrasco force-pushed the users/mgcarrasco/spirv/const_gep_fix branch from eaa43cc to 415ab60 Compare December 3, 2025 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants